﻿// --- Copyright (c) 2010 Steven Hartgers ---
// Copyright (C) 2010 Steven Hartgers All rights are reserved.
// Author contact: fiinix00/at\gmail.com
// ------------------------------------------------------------------------
// This program is free software: you can redistribute it and/or modify 
// it under the terms of the GNU General Public License as published by 
// the Free Software Foundation, either version 3 of the License, or 
// (at your option) any later version. 
//  
// This program is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
// GNU General Public License for more detail
//  
// You should have received a copy of the GNU General Public License 
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
// ------------------------------------------------------------------------
// COPYRIGHT NOTICE: This copyright notice may NOT be removed, obscured or modified 
// without written consent from the author.
// --- End copyright notice --- 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;

namespace Hack.SystemAPI
{
    public static class DataStructs
    {
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct DATA_BLOB
        {
            public int cbData;
            public IntPtr pbData;
        }
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct CRYPTPROTECT_PROMPTSTRUCT
        {
            public int cbSize;
            public int dwPromptFlags;
            public IntPtr hwndApp;
            public String szPrompt;
        }
        public static IntPtr NullPtr = ((IntPtr)((int)(0)));
        public const int CRYPTPROTECT_UI_FORBIDDEN = 0x1;
        public const int CRYPTPROTECT_LOCAL_MACHINE = 0x4;
    }
    public static class NativeDlls
    {
        [DllImport("user32", EntryPoint = "SendMessageA")]
        public static extern int SendMessage(int Hwnd, int wMsg, int wParam, int lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr FindWindow([MarshalAs(UnmanagedType.LPTStr)] string lpClassName, [MarshalAs(UnmanagedType.LPTStr)] string lpWindowName);
        
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int SendMessageA(IntPtr hwnd, int wMsg, int wParam, uint lParam);

        [DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        public static extern int GetWindowText(IntPtr hwnd, string lpString, int cch);

        [DllImport("user32", EntryPoint = "FindWindowExA")]
        public static extern int FindWindowEx(int hWnd1, int hWnd2, string lpsz1, string lpsz2);

        [DllImport("user32.dll")]
        public static extern int MessageBoxA(int hWnd, string strMsg, string strCaption, int iType);

        [DllImport("User32.dll")]
        public static extern bool MoveWindow(IntPtr handle, int x, int y, int width, int height, bool redraw);

        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool AbortSystemShutdown(string lpMachineName);

        [DllImport("advapi32", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool StartService(IntPtr hService, int dwNumServiceArgs,string[] lpServiceArgVectors);

        [DllImport("shell32.dll", EntryPoint = "ShellExecuteA")]
        public static extern int ShellExecute(int hwnd, String lpOperation, String lpFile, String lpParameters, String lpDirectory, int nShowCmd);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern string GetLastError();

        [DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        public unsafe static extern int FormatMessage(int dwFlags, ref IntPtr lpSource, int dwMessageId, int dwLanguageId, ref String lpBuffer, int nSize, IntPtr* Arguments);

        [DllImport("Crypt32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        public static extern bool CryptProtectData(ref Hack.SystemAPI.DataStructs.DATA_BLOB pDataIn, String szDataDescr, ref Hack.SystemAPI.DataStructs.DATA_BLOB pOptionalEntropy, IntPtr pvReserved, ref Hack.SystemAPI.DataStructs.CRYPTPROTECT_PROMPTSTRUCT pPromptStruct, int dwFlags, ref Hack.SystemAPI.DataStructs.DATA_BLOB pDataOut);
        
        [DllImport("Crypt32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        public static extern bool CryptUnprotectData(ref Hack.SystemAPI.DataStructs.DATA_BLOB pDataIn, String szDataDescr, ref Hack.SystemAPI.DataStructs.DATA_BLOB pOptionalEntropy, IntPtr pvReserved, ref Hack.SystemAPI.DataStructs.CRYPTPROTECT_PROMPTSTRUCT pPromptStruct, int dwFlags, ref Hack.SystemAPI.DataStructs.DATA_BLOB pDataOut);

        private static void InitPromptstruct(ref Hack.SystemAPI.DataStructs.CRYPTPROTECT_PROMPTSTRUCT ps)
        {
            ps.cbSize = Marshal.SizeOf(typeof(Hack.SystemAPI.DataStructs.CRYPTPROTECT_PROMPTSTRUCT));
            ps.dwPromptFlags = 0;
            ps.hwndApp = Hack.SystemAPI.DataStructs.NullPtr;
            ps.szPrompt = null;
        }
        public unsafe static String GetErrorMessage(int errorCode)
        {
            int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
            int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
            int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
            int messageSize = 255;
            String lpMsgBuf = "";
            int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
            IntPtr ptrlpSource = new IntPtr();
            IntPtr prtArguments = new IntPtr();
            int retVal = FormatMessage(dwFlags, ref ptrlpSource, errorCode, 0, ref lpMsgBuf, messageSize, &prtArguments);

            if (0 == retVal)
            {
                throw new Exception("Failed to format message for error code " + errorCode + ". ");
            }

            return lpMsgBuf;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ProcessHandle">handle to process</param>
        /// <param name="DesiredAccess">desired access to process</param>
        /// <param name="TokenHandle">handle to open access token</param>
        /// <returns></returns>
        [DllImport("advapi32")]
        public static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);

        [DllImport("advapi32.dll", EntryPoint="RegDeleteKeyTransactedW")]
        public static extern long RegDeleteKeyTransacted(uint hkey, [MarshalAs(UnmanagedType.LPWStr)]string subkey, uint sam, uint reserved, IntPtr transaction, IntPtr reserved2);
  
        [DllImport("Kernel32.dll")]
        public static extern bool CloseHandle(IntPtr handle);

        /// <summary>
        /// Get internal memmory handle from integer value
        /// 
        /// Console output handle = -11
        /// Console input handle = -10
        /// Console error handle = -12
        /// </summary>
        /// <param name="nStdHandle"></param>
        /// <returns></returns>
        [DllImportAttribute("Kernel32.dll")]
        public static extern IntPtr GetStdHandle(int nStdHandle);

        [DllImport("user32.dll")]
        public static extern int GetForegroundWindow();

        [DllImport("user32.dll")]
        public static extern int GetWindowText(int hWnd, StringBuilder text, int count);

        [DllImport("user32.dll")]
        public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [DllImport("user32.dll", EntryPoint = "SendMessageW")]
        public static extern IntPtr SendMessageByString(HandleRef hWnd, UInt32 Msg, IntPtr wParam, StringBuilder lParam);

        [DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "SendMessageW")]
        public static extern IntPtr SendMessageByString(HandleRef hWnd, UInt32 Msg, IntPtr wParam, String lParam);

        [DllImport("kernel32")]
        public extern static int LoadLibrary(string librayName);

        [DllImport("User32.dll")]
        public static extern IntPtr LoadImage(IntPtr hInstance, int uID, uint type, int width, int height, int load);
        
        [DllImport("User32.dll")]
        public static extern IntPtr LoadBitmap(IntPtr hInstance, int uID);

        [DllImport("kernel32.dll")]
        public static extern IntPtr FindResource(IntPtr hModule, int lpID, string lpType);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo);

        [DllImport("User32.dll")]
        public static extern int LoadString(IntPtr hInstance, int uID, StringBuilder lpBuffer, int nBufferMax);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, dwFlags dwFlags);

        [DllImport("kernel32")]
        public extern static bool FreeLibrary(int hLibModule);

        [DllImport("kernel32", CharSet = CharSet.Ansi)]
        public extern static int GetProcAddress(int hModule, string lpProcName);

        [DllImport("shell32.dll", EntryPoint = "ExtractIcon")]
        public static extern IntPtr ExtractIcon(IntPtr hInst, string lpszExeFileName, int nIconIndex);

        [DllImport("shell32.dll")]
        public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);
        
        [DllImport("User32.dll")]
        public static extern int DestroyIcon(IntPtr hIcon);

    }
    public enum dwFlags : uint
    {
        DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
        LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
        LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008,
        LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
        LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
        LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040
    }
    public static class SoundManager
    {
        public static class VolumeStructs
        {
            /// <summary>
            /// struct for holding data for the mixer caps
            /// </summary>
            public struct MixerCaps
            {
                public int wMid;
                public int wPid;
                public int vDriverVersion;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = VolumeConstants.MAXPNAMELEN)]
                public string szPname;
                public int fdwSupport;
                public int cDestinations;
            }

            /// <summary>
            /// struct to hold data for the mixer control
            /// </summary>
            public struct Mixer
            {
                public int cbStruct;
                public int dwControlID;
                public int dwControlType;
                public int fdwControl;
                public int cMultipleItems;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = VolumeConstants.MIXER_SHORT_NAME_CHARS)]
                public string szShortName;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = VolumeConstants.MIXER_LONG_NAME_CHARS)]
                public string szName;
                public int lMinimum;
                public int lMaximum;
                [MarshalAs(UnmanagedType.U4, SizeConst = 10)]
                public int reserved;
            }

            /// <summary>
            /// struct for holding data about the details of the mixer control
            /// </summary>
            public struct MixerDetails
            {
                public int cbStruct;
                public int dwControlID;
                public int cChannels;
                public int item;
                public int cbDetails;
                public IntPtr paDetails;
            }

            /// <summary>
            /// struct to hold data for an unsigned mixer control details
            /// </summary>
            public struct UnsignedMixerDetails
            {
                public int dwValue;
            }

            /// <summary>
            /// struct to hold data for the mixer line
            /// </summary>
            public struct MixerLine
            {
                public int cbStruct;
                public int dwDestination;
                public int dwSource;
                public int dwLineID;
                public int fdwLine;
                public int dwUser;
                public int dwComponentType;
                public int cChannels;
                public int cConnections;
                public int cControls;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = VolumeConstants.MIXER_SHORT_NAME_CHARS)]
                public string szShortName;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = VolumeConstants.MIXER_LONG_NAME_CHARS)]
                public string szName;
                public int dwType;
                public int dwDeviceID;
                public int wMid;
                public int wPid;
                public int vDriverVersion;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = VolumeConstants.MAXPNAMELEN)]
                public string szPname;
            }

            /// <summary>
            /// struct for holding data for the mixer line controls
            /// </summary>
            public struct LineControls
            {
                public int cbStruct;
                public int dwLineID;
                public int dwControl;
                public int cControls;
                public int cbmxctrl;
                public IntPtr pamxctrl;
            }
        }

        /// <summary>
        /// method for retrieving the current volume from the system
        /// </summary>
        /// <returns>int value</returns>
        public static int GetVolume()
        {
            //method level variables
            int currVolume;
            int mixerControl;

            //create a new volume control
            VolumeStructs.Mixer mixer = new VolumeStructs.Mixer();

            //open the mixer
            PCWin32.mixerOpen(out mixerControl, 0, 0, 0, 0);

            //set the type to volume control type
            int type = VolumeConstants.MIXERCONTROL_CONTROLTYPE_VOLUME;

            //get the mixer control and get the current volume level
            GetMixer(mixerControl, VolumeConstants.MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, type, out mixer, out currVolume);

            //close the mixer control since we are now done with it
            PCWin32.mixerClose(mixerControl);

            //return the current volume to the calling method
            return currVolume;
        }


        /// <summary>
        /// method for setting the value for a volume control
        /// </summary>
        /// <param name="i"></param>
        /// <param name="mixerControl"></param>
        /// <param name="volumeLevel"></param>
        /// <returns>true/false</returns>
        private static bool SetMixer(int i, VolumeStructs.Mixer mixerControl, int volumeLevel)
        {
            //method level variables
            bool bReturn;
            int details;

            //create our struct object for controlling the system sound
            VolumeStructs.MixerDetails mixerDetails = new VolumeStructs.MixerDetails();
            VolumeStructs.UnsignedMixerDetails volume = new VolumeStructs.UnsignedMixerDetails();

            //set out mixer control properties
            mixerDetails.item = 0;
            //set the id of the mixer control
            mixerDetails.dwControlID = mixerControl.dwControlID;
            //return the size of the mixer details struct
            mixerDetails.cbStruct = Marshal.SizeOf(mixerDetails);
            //return the volume
            mixerDetails.cbDetails = Marshal.SizeOf(volume);

            //Allocate a buffer for the mixer control value buffer
            mixerDetails.cChannels = 1;
            volume.dwValue = volumeLevel;

            //Copy the data into the mixer control value buffer
            mixerDetails.paDetails = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(VolumeStructs.UnsignedMixerDetails)));
            Marshal.StructureToPtr(volume, mixerDetails.paDetails, false);

            //Set the control value
            details = PCWin32.mixerSetControlDetails(i, ref mixerDetails, VolumeConstants.MIXER_SETCONTROLDETAILSF_VALUE);

            //Check to see if any errors were returned
            if (VolumeConstants.MMSYSERR_NOERROR == details)
            {
                bReturn = true;
            }
            else
            {
                bReturn = false;
            }
            return bReturn;

        }

        /// <summary>
        /// method to retrieve a mixer control
        /// </summary>
        /// <param name="i"></param>
        /// <param name="type"></param>
        /// <param name="ctrlType"></param>
        /// <param name="mixerControl"></param>
        /// <param name="currVolume"></param>
        /// <returns></returns>
        private static bool GetMixer(int i, int type, int ctrlType, out VolumeStructs.Mixer mixerControl, out int currVolume)
        {
            //create our method level variables
            int details;
            bool bReturn;
            currVolume = -1;

            //create our struct objects
            VolumeStructs.LineControls lineControls = new VolumeStructs.LineControls();
            VolumeStructs.MixerLine line = new VolumeStructs.MixerLine();
            VolumeStructs.MixerDetails mcDetails = new VolumeStructs.MixerDetails();
            VolumeStructs.UnsignedMixerDetails detailsUnsigned = new VolumeStructs.UnsignedMixerDetails();

            //create a new mixer control
            mixerControl = new VolumeStructs.Mixer();

            //set the properties of out mixerline object
            line.cbStruct = Marshal.SizeOf(line);
            line.dwComponentType = type;
            //get the line info and assign it to our details variable
            details = PCWin32.mixerGetLineInfoA(i, ref line, VolumeConstants.MIXER_GETLINEINFOF_COMPONENTTYPE);

            //make sure we didnt receive any errors
            if (VolumeConstants.MMSYSERR_NOERROR == details)
            {
                int mcSize = 152;
                //get the size of the unmanaged type
                int control = Marshal.SizeOf(typeof(VolumeStructs.Mixer));
                //allocate a block of memory
                lineControls.pamxctrl = Marshal.AllocCoTaskMem(mcSize);
                //get the size of the line controls
                lineControls.cbStruct = Marshal.SizeOf(lineControls);

                //set properties for our mixer control
                lineControls.dwLineID = line.dwLineID;
                lineControls.dwControl = ctrlType;
                lineControls.cControls = 1;
                lineControls.cbmxctrl = mcSize;

                // Allocate a buffer for the control
                mixerControl.cbStruct = mcSize;

                // Get the control
                details = PCWin32.mixerGetLineControlsA(i, ref lineControls, VolumeConstants.MIXER_GETLINECONTROLSF_ONEBYTYPE);

                //once again check to see if we received any errors
                if (VolumeConstants.MMSYSERR_NOERROR == details)
                {
                    bReturn = true;
                    //Copy the control into the destination structure
                    mixerControl = (VolumeStructs.Mixer)Marshal.PtrToStructure(lineControls.pamxctrl, typeof(VolumeStructs.Mixer));
                }
                else
                {
                    bReturn = false;
                }

                int mcDetailsSize = Marshal.SizeOf(typeof(VolumeStructs.MixerDetails));
                int mcDetailsUnsigned = Marshal.SizeOf(typeof(VolumeStructs.UnsignedMixerDetails));
                mcDetails.cbStruct = mcDetailsSize;
                mcDetails.dwControlID = mixerControl.dwControlID;
                mcDetails.paDetails = Marshal.AllocCoTaskMem(mcDetailsUnsigned);
                mcDetails.cChannels = 1;
                mcDetails.item = 0;
                mcDetails.cbDetails = mcDetailsUnsigned;
                details = PCWin32.mixerGetControlDetailsA(i, ref mcDetails, VolumeConstants.MIXER_GETCONTROLDETAILSF_VALUE);
                detailsUnsigned = (VolumeStructs.UnsignedMixerDetails)Marshal.PtrToStructure(mcDetails.paDetails, typeof(VolumeStructs.UnsignedMixerDetails));
                currVolume = detailsUnsigned.dwValue;
                return bReturn;
            }

            bReturn = false;
            return bReturn;
        }

        /// <summary>
        /// method for setting the volume to a specific level
        /// </summary>
        /// <param name="volumeLevel">volume level we wish to set volume to</param>
        public static void SetVolume(int volumeLevel)
        {
            try
            {
                //method level variables
                int currVolume;
                int mixerControl;

                //create a new volume control
                VolumeStructs.Mixer volumeControl = new VolumeStructs.Mixer();

                //open the mixer control
                PCWin32.mixerOpen(out mixerControl, 0, 0, 0, 0);

                //set the type to volume control type
                int controlType = VolumeConstants.MIXERCONTROL_CONTROLTYPE_VOLUME;

                //get the current mixer control and get the current volume
                GetMixer(mixerControl, VolumeConstants.MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, controlType, out volumeControl, out currVolume);

                //now check the volume level. If the volume level
                //is greater than the max then set the volume to
                //the max level. If it's less than the minimum level
                //then set it to the minimun level
                if (volumeLevel > volumeControl.lMaximum)
                {
                    volumeLevel = volumeControl.lMaximum;
                }
                else if (volumeLevel < volumeControl.lMinimum)
                {
                    volumeLevel = volumeControl.lMinimum;
                }

                //set the volume
                SetMixer(mixerControl, volumeControl, volumeLevel);

                //now re-get the mixer control
                GetMixer(mixerControl, VolumeConstants.MIXERLINE_COMPONENTTYPE_DST_SPEAKERS, controlType, out volumeControl, out currVolume);

                //make sure the volume level is equal to the current volume
                if (volumeLevel != currVolume)
                {
                    throw new Exception("Cannot Set Volume");
                }

                //close the mixer control as we are finished with it
                PCWin32.mixerClose(mixerControl);
            }
            catch (Exception ex)
            {
                AnytimeMessageBox.Say(ex.Message, "Error");
            }
        }


        /// <summary>
        /// struct for holding data for the mixer caps
        /// </summary>
        public struct MixerCaps
        {
            public int wMid;
            public int wPid;
            public int vDriverVersion;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = VolumeConstants.MAXPNAMELEN)]
            public string szPname;
            public int fdwSupport;
            public int cDestinations;
        }

        /// <summary>
        /// struct to hold data for the mixer control
        /// </summary>
        public struct Mixer
        {
            public int cbStruct;
            public int dwControlID;
            public int dwControlType;
            public int fdwControl;
            public int cMultipleItems;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = VolumeConstants.MIXER_SHORT_NAME_CHARS)]
            public string szShortName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = VolumeConstants.MIXER_LONG_NAME_CHARS)]
            public string szName;
            public int lMinimum;
            public int lMaximum;
            [MarshalAs(UnmanagedType.U4, SizeConst = 10)]
            public int reserved;
        }

        /// <summary>
        /// struct for holding data about the details of the mixer control
        /// </summary>
        public struct MixerDetails
        {
            public int cbStruct;
            public int dwControlID;
            public int cChannels;
            public int item;
            public int cbDetails;
            public IntPtr paDetails;
        }

        /// <summary>
        /// struct to hold data for the mixer line
        /// </summary>
        public struct MixerLine
        {
            public int cbStruct;
            public int dwDestination;
            public int dwSource;
            public int dwLineID;
            public int fdwLine;
            public int dwUser;
            public int dwComponentType;
            public int cChannels;
            public int cConnections;
            public int cControls;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = VolumeConstants.MIXER_SHORT_NAME_CHARS)]
            public string szShortName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = VolumeConstants.MIXER_LONG_NAME_CHARS)]
            public string szName;
            public int dwType;
            public int dwDeviceID;
            public int wMid;
            public int wPid;
            public int vDriverVersion;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = VolumeConstants.MAXPNAMELEN)]
            public string szPname;
        }

        /// <summary>
        /// Class to hold all the constants needed for controlling the system sound
        /// </summary>
        public static class VolumeConstants
        {
            public const int MMSYSERR_NOERROR = 0;
            public const int MAXPNAMELEN = 32;
            public const int MIXER_LONG_NAME_CHARS = 64;
            public const int MIXER_SHORT_NAME_CHARS = 16;
            public const int MIXER_GETLINEINFOF_COMPONENTTYPE = 0x3;
            public const int MIXER_GETCONTROLDETAILSF_VALUE = 0x0;
            public const int MIXER_GETLINECONTROLSF_ONEBYTYPE = 0x2;
            public const int MIXER_SETCONTROLDETAILSF_VALUE = 0x0;
            public const int MIXERLINE_COMPONENTTYPE_DST_FIRST = 0x0;
            public const int MIXERLINE_COMPONENTTYPE_SRC_FIRST = 0x1000;
            public const int MIXERCONTROL_CT_CLASS_FADER = 0x50000000;
            public const int MIXERCONTROL_CT_UNITS_UNSIGNED = 0x30000;
            public const int MIXERCONTROL_CONTROLTYPE_FADER = (MIXERCONTROL_CT_CLASS_FADER | MIXERCONTROL_CT_UNITS_UNSIGNED);
            public const int MIXERCONTROL_CONTROLTYPE_VOLUME = (MIXERCONTROL_CONTROLTYPE_FADER + 1);
            public const int MIXERLINE_COMPONENTTYPE_DST_SPEAKERS = (MIXERLINE_COMPONENTTYPE_DST_FIRST + 4);
            public const int MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 3);
            public const int MIXERLINE_COMPONENTTYPE_SRC_LINE = (MIXERLINE_COMPONENTTYPE_SRC_FIRST + 2);
        }

        /// <summary>
        /// struct for holding data for the mixer line controls
        /// </summary>
        public struct LineControls
        {
            public int cbStruct;
            public int dwLineID;
            public int dwControl;
            public int cControls;
            public int cbmxctrl;
            public IntPtr pamxctrl;
        }

        /// <summary>
        /// struct to hold data for an unsigned mixer control details
        /// </summary>
        public struct UnsignedMixerDetails
        {
            public int dwValue;
        }

        /// <summary>
        /// Class that contains all the Win32 API calls
        /// we need for controlling the system sound
        /// </summary>
        public static class PCWin32
        {
            [DllImport("winmm.dll", CharSet = CharSet.Ansi)]
            public static extern int mixerClose(int hmx);

            [DllImport("winmm.dll", CharSet = CharSet.Ansi)]
            public static extern int mixerGetControlDetailsA(int hmxobj, ref VolumeStructs.MixerDetails pmxcd, int fdwDetails);

            [DllImport("winmm.dll", CharSet = CharSet.Ansi)]
            public static extern int mixerGetDevCapsA(int uMxId, VolumeStructs.MixerCaps pmxcaps, int cbmxcaps);

            [DllImport("winmm.dll", CharSet = CharSet.Ansi)]
            public static extern int mixerGetID(int hmxobj, int pumxID, int fdwId);

            [DllImport("winmm.dll", CharSet = CharSet.Ansi)]
            public static extern int mixerGetLineControlsA(int hmxobj, ref VolumeStructs.LineControls pmxlc, int fdwControls);

            [DllImport("winmm.dll", CharSet = CharSet.Ansi)]
            public static extern int mixerGetLineInfoA(int hmxobj, ref VolumeStructs.MixerLine pmxl, int fdwInfo);

            [DllImport("winmm.dll", CharSet = CharSet.Ansi)]
            public static extern int mixerGetNumDevs();

            [DllImport("winmm.dll", CharSet = CharSet.Ansi)]
            public static extern int mixerMessage(int hmx, int uMsg, int dwParam1, int dwParam2);

            [DllImport("winmm.dll", CharSet = CharSet.Ansi)]
            public static extern int mixerOpen(out int phmx, int uMxId, int dwCallback, int dwInstance, int fdwOpen);

            [DllImport("winmm.dll", CharSet = CharSet.Ansi)]
            public static extern int mixerSetControlDetails(int hmxobj, ref VolumeStructs.MixerDetails pmxcd, int fdwDetails);
        }
    }
    public static class CDDrives
    {
        [DllImport("winmm.dll", EntryPoint = "mciSendStringA", CharSet = CharSet.Ansi)]
        public static extern int mciSendString(string lpstrCommand, StringBuilder lpstrReturnString, int uReturnLength, IntPtr hwndCallback);

        [DllImport("winmm.dll", EntryPoint = "mciSendString")]
        public static extern int mciSendStringA(string lpstrCommand, string lpstrReturnString, int uReturnLength, int hwndCallback);

        public static void OpenDrive(string driveRoot)
        {
            string driveLetter = driveRoot[0].ToString();
            string returnString = string.Empty;

            //Set a name for the specified disk drive
            mciSendStringA("open " + driveLetter + ": type CDaudio alias drive" + driveLetter, returnString, 0, 0);

            //open the disk tray
            mciSendStringA("set drive" + driveLetter + " door open", returnString, 0, 0);
        }
        public static void CloseDrive(string driveRoot)
        {
            string driveLetter = driveRoot[0].ToString();
            string returnString = string.Empty;

            //Set a name for the specified disk drive
            mciSendStringA("open " + driveLetter + ": type CDaudio alias drive" + driveLetter, returnString, 0, 0);

            //close the disk tray
            mciSendStringA("set drive" + driveLetter + " door closed", returnString, 0, 0);
        }

        public static DriveInfo[] getDrives()
        {
            return DriveInfo.GetDrives();
        }
        public static DirectoryInfo GetRoot(this DriveInfo drive)
        {
            return drive.RootDirectory;
        }
        public static DirectoryInfo[] GetRoots(this DriveInfo[] drives)
        {
            DirectoryInfo[] driveInfos = new DirectoryInfo[drives.Length];

            for (int drive = 0; drive < drives.Length; drive++)
            {
                driveInfos[drive] = drives[drive].RootDirectory;
            }
            return driveInfos;
        }
    }
    public static class WindowManager
    {
        [DllImport("user32.dll")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

        public static bool SetForegroundWindow(ProcessWindow window)
        {
            if ((IntPtr)window.Handle != null)
            {
                return SetForegroundWindow((IntPtr)window.Handle);
            }
            return false;
        }

        public class ProcessWindow
        {
            public IntPtr? Handle { get; internal set; }

            /// <summary>
            /// Returns Null if not exists
            /// </summary>
            /// <param name="processName"></param>
            public ProcessWindow(String processName)
            {
                Handle = null;

                System.Diagnostics.Process[] p = System.Diagnostics.Process.GetProcessesByName(processName);
                if (p.Length > 0)
                {
                    this.Handle = p[0].MainWindowHandle;
                }
            }
        }
    }
}